/* 
 * File:   wiwannBuffer.h
 * Author: manu
 *
 * Created on 24 novembre 2010, 11:30
 */

#ifndef _WIWANNBASEBUFFER_H
#define	_WIWANNBASEBUFFER_H


#include "wiwannTypes.h"
#include "wiwannEvent.h"

#include <string.h>
#include <iostream>



class wiwannBaseBuffer
{
    //cas d'usage reflexion impliquant les wiwannComplexBuffer :
    //on prépare un buffer  à recevoir tant de données
    //on recopie un buffer
    //on ajoute de la donnée (ou un buffer
    //) à un buffer existant (taille auto gérée )
    //pour cela il faudra que le buffer puisse avoir des sous-buffers fils
    //si de la donnée a déjà été utilisée et n'est plus nécessaire il faudra dé-queuer et liberer la mémoire en fonction

    //wiwannBaseBuffer cas d'usage:
    //preparation d'un buffer à recevoir tant de donnée maxi
    //creation d'un buffer clone

private :

    WIWANNdontcare *pointerTmp ;
    WIWANNuint sizeChar ;
    WIWANNdontcare *pointer ;

public :

    wiwannEvent creationEvent ;

    wiwannBaseBuffer(WIWANNdontcare * pointerExt)
    {
        this->sizeChar = 0 ;
        this->pointer = pointerExt ;
        this->pointerTmp = pointerExt ;
        this->creationEvent = new wiwannEvent();
    }

    wiwannBaseBuffer(WIWANNdontcare * pointerExt,wiwannEvent *wwnEvent)
    {
        this->creationEvent = *wwnEvent ;
        this->wiwannBaseBuffer(pointerExt)  ;
    }

    wiwannBaseBuffer(const WIWANNdontcare * pointerExt, WIWANNsize sizeCharExt)
    {
        this->setAlloc(sizeCharExt);
        this->creationEvent = new wiwannEvent();
        if( this->isValid() )
            this->feed(pointerExt,sizeCharExt);
    }

    wiwannBaseBuffer(const WIWANNdontcare * pointerExt,wiwannEvent *wwnEvent)
    {
        this->creationEvent = *wwnEvent ;
        this->wiwannBaseBuffer(pointerExt)  ;
    }

    wiwannEvent *getCreationEvent()
    {
        return &this->creationEvent ;
    }
    

    wiwannBaseBuffer(WIWANNsize sizeCharExt)
    {
        this->setAlloc(sizeCharExt);
    }

    void setAlloc(WIWANNsize sizeCharExt)
    {
        std::cout << "\nentree dans le constructeyr par taille" ;
        this->pointer = malloc(sizeCharExt); //we sacrify one more char to not care about end string character
        if( ! this->pointer )
        {
            this->pointerTmp = NULL ;
            this->sizeChar = 0 ;
        }
        this->sizeChar = sizeCharExt ;
        this->pointerTmp = this->pointer ;
        std::cout << "\nel constructor baseBuffer " <<  this->pointer;
    }

     std::string toString()
    {
        std::string *s = new std::string((char *) this->getStartAdress(),( unsigned int ) this->getSize());
        return *s ;
    }

     void rewind()
     {
         this->pointerTmp = pointer ;
     }



    WIWANNdontcare * getPointerFor(WIWANNsize sizeCharExt)
    {
        this->pointerTmp=  (char *) this->pointerTmp + sizeCharExt ;
        return this->pointerTmp ;
    }

    /**
     * feed the buffer with const existent data
     */

    WIWANNdontcare * feed(const WIWANNdontcare * pointerExt, WIWANNsize sizeCharExt)
    {
        memcpy ( this->pointerTmp , pointerExt, sizeCharExt );
        this->pointerTmp = (char *) this->pointerTmp + sizeCharExt ;
        return this->pointerTmp ;
    }

    //return the data pointer, and assure it wont be unallocated
    WIWANNdontcare * consume()
    {
        WIWANNdontcare * retPoint = this->pointer ;
        this->pointer = NULL ;
        return retPoint ;
    }

    bool get(const WIWANNdontcare * pointerExt, WIWANNsize sizeCharExt)
    {
        if( this->getRestingSize() >= sizeCharExt )
        {

            if( memcpy ( pointerExt , this->pointerTmp ) )
            {
                this->pointerTmp = this->pointerTmp + sizeCharExt ;
                return true ;
            }
        }
        return false ;
    }


    bool get(wiwannBaseBuffer *wwnBB)
    {
        wwnBB = wiwannBaseBuffer::cloneFromData(this->pointerTmp,this->getRestingSize());
    }

    


        bool isAtStart()
        {
            return this->pointer == this->pointerTmp ;
        }



    bool isReadyFor(WIWANNsize sizeCharExt)
    {
        return ( ( (char *) this->pointerTmp + sizeCharExt ) <= ( (char *) this->pointer + this->sizeChar ) ) ;
    }

    bool isValid()
    {
        if( this->pointerTmp < ( (char *) this->pointer + this->sizeChar) );
            return (bool) this->pointer ;
        return false ;
    }

    WIWANNdontcare *getStartAdress()
    {
        return this->pointer ;
    }

    WIWANNdontcare *getReadAdress()
    {
        return this->pointerTmp ;
    }

    WIWANNdontcare read(WIWANNdontcare *extPointer,WIWANNsize *extSize)
    {
        WIWANNsize restingSize = this->getRestingSize() ;
        if( *extSize > restingSize )
            *extSize = restingSize ;
        memcpy(extPointer,this->pointerTmp,*extSize);
        this->pointerTmp = *extSize + (char *) this->pointerTmp ;
    }

    bool isRead()
    {
        return this->pointerTmp >= ( this->sizeChar + (char *) this->pointer ) ;
    }

    WIWANNsize getRestingSize()
    {
        return ( (char *) this->pointer + this->sizeChar ) - ( (char *) this->pointerTmp ) ;
    }



    ~wiwannBaseBuffer()
    {
        //std::cout << "\nel destructor baseBuffer " <<  this->pointer;
        free(this->pointer);
        this->sizeChar = 0 ;
        this->pointer = NULL ;
    };

    void setSize(WIWANNuint Csize)
    {
        this->sizeChar = Csize ;
    }

    WIWANNuint getSize()
    {
        return this->sizeChar ;
    }
    
    static wiwannBaseBuffer *makeFromData(WIWANNdontcare * pointerExt, WIWANNsize sizeCharExt)
    {
        wiwannBaseBuffer *wwnBuffer = new wiwannBaseBuffer( pointerExt);
        wwnBuffer->setSize(sizeCharExt);
        return wwnBuffer ;
    }

    static wiwannBaseBuffer *cloneFromData(const WIWANNdontcare * pointerExt, WIWANNsize sizeCharExt)
    {
        wiwannBaseBuffer *wwnBuffer = new wiwannBaseBuffer(pointerExt,sizeCharExt);
        if(wwnBuffer->isValid())
        {
            return NULL ;
        }
        return wwnBuffer ;
    }


};

std::ostream & operator<<( std::ostream & os, wiwannBaseBuffer * wwnBB )
{
    os << wwnBB->toString() ;
}

std::istream & operator>>
( std::istream & is, wiwannBaseBuffer * wwnBB )
{
    std::string s ;
    is >> s  ;
    wwnBB->feed(s.c_str(),s.size());
}

#endif	/* _WIWANNBASEBUFFER_H */

